package spring_boot.corona.track.experiment3.services;

import org.apache.commons.csv.CSVFormat;
import org.apache.commons.csv.CSVRecord;
import org.springframework.core.io.Resource;
import org.springframework.http.HttpHeaders;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.web.reactive.function.client.ClientResponse;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.core.publisher.Mono;
import spring_boot.corona.track.experiment3.models.RegionStats;

import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Reader;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @Author: 王志华
 * @Date: 2020/11/11
 */
@Service
public class GetDataService {

    // 数据所在仓库地址
    private static final String baseUrl = "https://gitee.com/Kim_zhihua/COVID-19/raw/master/csse_covid_19_data/csse_covid_19_time_series/time_series_covid19_confirmed_global.csv";

    // 将所有数据对象组织成一个list，方便后续访问调用
    private final List<RegionStats> allRegionStats = new ArrayList<>();

    // 国家名列表，用于html页面提供查询选择
    private final List<String> countryList = new ArrayList<>();

    // 创建对象时自动调用方法来分析数据
    public GetDataService() {
        parseData();
    }

    public List<RegionStats> getAllRegionStats() {
        return allRegionStats;
    }

    public ClientResponse getDataResponse() {

        // 使用WebClient爬取网站数据
        WebClient webClient = WebClient.builder()
                .baseUrl(baseUrl)
                .defaultHeader(HttpHeaders.USER_AGENT, "Mozilla/5.0")
                .codecs(configurer -> configurer.defaultCodecs().maxInMemorySize(2 * 1024 * 1024))  // 修改最大内存限制为2M
                .build();

        Mono<ClientResponse> mono = webClient
                .get()
                .exchange();

        return mono.block();

    }

    // 处理爬取的csv数据
    // 每天凌晨1点爬取gitee仓库上的全球确诊病例
    @Scheduled(cron = "${wzh.Schedules.updateDataCron}")
    public void parseData() {

        ClientResponse response = getDataResponse();  // 获取数据对象
        assert response != null;

        // 将数据对象转为Resource对象以供Commons CSV组件进行处理
        Resource resource = response.bodyToMono(Resource.class).block();  // 将数据对象转为Resource对象以供Commons CSV组件进行处理

        try {
            assert resource != null;
            Reader in = new InputStreamReader(resource.getInputStream(), StandardCharsets.UTF_8);
            Iterable<CSVRecord> records = CSVFormat.EXCEL.parse(in);
            boolean firstLine = true;  // 标记是否为第一行
            List<String> dateList = new ArrayList<>();  // 用于记录所有日期
            for (CSVRecord record : records) {
                if (firstLine) {
                    // if语句中内容必执行一次，用于处理数据第一行（忽略"Province/State,Country/Region,Lat,Long,"4个标题，并获取所有日期）
                    // 执行一次后将条件置为false
                    firstLine = false;
                    // 从最后一个日期(最新的日期)开始写入列表
                    for (int i = record.size() - 1; i >= 4; --i) {
                        String[] split = record.get(i).split("/");
                        dateList.add("20" + split[2] + "." + split[0] + "." + split[1]);  // 改变格式为20**.*.*，如2020.11.11
                    }
                } else {
                    // 处理数据
                    RegionStats regionStats = new RegionStats();

                    // 图dayAdd保存的是形如"日期：当日确诊数"的数据形式
                    Map<String, Integer> dayAdd = new HashMap<>();
                    for (int i = record.size() - 1, j = 0; i >= 4; --i, ++j) {
                        dayAdd.put(dateList.get(j), i > 4 ? (Integer.parseInt(record.get(i)) - Integer.parseInt(record.get(i - 1)))
                                : (Integer.parseInt(record.get(i))));
                    }

                    regionStats.setState(record.get(0));    // "Province/State"
                    regionStats.setCountry(record.get(1));  // "Country/Region"
                    regionStats.setDayAdd(dayAdd);
                    regionStats.setDateList(dateList);
                    regionStats.setLatestTotalCases(Integer.parseInt(record.get(record.size() - 1)));
                    allRegionStats.add(regionStats);
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    // 获取去重后的国家名列表
    public List<String> getDeduplicationCountry(List<RegionStats> list) {

        // 通过for each循环用国家名初始化countryList
        for (RegionStats temp : list) {
            countryList.add(temp.getCountry());
        }

        for (int i = 0; i < countryList.size() - 1; ++i) {
            for (int j = countryList.size() - 1; j > i; --j) {
                if (countryList.get(i).equals(countryList.get(j))) {
                    countryList.remove(j);    // 去重
                }
            }
        }
        return countryList;
    }

}
